package org.dromara.business.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.dromara.business.domain.*;
import org.dromara.business.domain.vo.UserInfoWebExtVo;
import org.dromara.business.domain.vo.VideoVo;
import org.dromara.business.mapper.*;
import org.dromara.common.core.constant.BusinessConstants;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.annotation.DataPermission;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysLogininfor;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.domain.vo.UserInfoVo;
import org.dromara.system.mapper.SysLogininforMapper;
import org.dromara.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;
import org.dromara.business.domain.bo.UserInfoWebBo;
import org.dromara.business.domain.vo.UserInfoWebVo;
import org.dromara.business.service.IUserInfoService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户附加信息Service业务层处理
 *
 * @author Hao Tong Xue
 * @date 2025-04-03
 */
@RequiredArgsConstructor
@Service
@Transactional(rollbackFor = Exception.class)
public class UserInfoServiceImpl implements IUserInfoService {

    private final UserInfoMapper baseMapper;

    private final SysUserMapper sysUserMapper;

    private final UserFollowMapper userFollowMapper;

    private final UserLevelMapper userLevelMapper;

    private final UserCoinLogMapper userCoinLogMapper;

    private final UserLevelExperienceLogMapper userLevelExperienceLogMapper;

    private final VideoMapper videoMapper;

    private final UserCollectMapper collectMapper;

    private final ContentCollectionMapper collectionMapper;

    /**
     * 查询用户附加信息
     *
     * @param id 主键
     * @return 用户附加信息
     */
    @Override
    public UserInfoWebVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询用户附加信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 用户附加信息分页列表
     */
    @Override
    public TableDataInfo<UserInfoWebVo> queryPageList(UserInfoWebBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<UserInfoWeb> lqw = buildQueryWrapper(bo);
        Page<UserInfoWebVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<UserInfoWebVo> records = result.getRecords();
        if (CollUtil.isNotEmpty(records)) {

            List<SysUserVo> userVoList = DataPermissionHelper.ignore(() -> sysUserMapper.selectVoByIds(records.stream().map(UserInfoWebVo::getId).toList()));

            Map<Long, SysUserVo> sysUserVoMap = userVoList.stream().collect(Collectors.toMap(SysUserVo::getUserId, s -> s));

            List<UserLevel> userLevelList = userLevelMapper.selectList();
            Map<Long, Integer> userLevelMap = userLevelList.stream().collect(Collectors.toMap(UserLevel::getId, UserLevel::getUserLevel));

            for (UserInfoWebVo record : records) {
                record.setUserVo(sysUserVoMap.get(record.getId()));
                record.setCurrentUserLevel(userLevelMap.get(record.getUserLevelId()));
            }

        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的用户附加信息列表
     *
     * @param bo 查询条件
     * @return 用户附加信息列表
     */
    @Override
    public List<UserInfoWebVo> queryList(UserInfoWebBo bo) {
        LambdaQueryWrapper<UserInfoWeb> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<UserInfoWeb> buildQueryWrapper(UserInfoWebBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<UserInfoWeb> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(UserInfoWeb::getId);
        lqw.eq(StringUtils.isNotBlank(bo.getSignature()), UserInfoWeb::getSignature, bo.getSignature());
        lqw.eq(bo.getBalance() != null, UserInfoWeb::getBalance, bo.getBalance());
        lqw.eq(bo.getBirthday() != null, UserInfoWeb::getBirthday, bo.getBirthday());
        if (StrUtil.isNotEmpty(bo.getUserNickName()) || StrUtil.isNotEmpty(bo.getTel())) {

            List<SysUser> sysUserList = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery().likeRight(StrUtil.isNotEmpty(bo.getUserNickName()), SysUser::getNickName, bo.getUserNickName()).eq(StrUtil.isNotEmpty(bo.getTel()), SysUser::getPhonenumber, bo.getTel()));
            if (CollUtil.isNotEmpty(sysUserList)) {

                lqw.in(UserInfoWeb::getId, sysUserList.stream().map(SysUser::getUserId).collect(Collectors.toList()));

            }else {
                lqw.eq(UserInfoWeb::getId, -1);
            }

        }
        lqw.orderByDesc(BaseEntity::getCreateTime);
        return lqw;
    }

    /**
     * 新增用户附加信息
     *
     * @param bo 用户附加信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(UserInfoWebBo bo) {
        UserInfoWeb add = MapstructUtils.convert(bo, UserInfoWeb.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改用户附加信息
     *
     * @param bo 用户附加信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(UserInfoWebBo bo) {
        UserInfoWeb update = MapstructUtils.convert(bo, UserInfoWeb.class);
        if (bo.getUserVo() != null) {
            SysUser sysUser = MapstructUtils.convert(bo.getUserVo(), SysUser.class);
            sysUserMapper.updateById(sysUser);
        }
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(UserInfoWeb entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除用户附加信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 获取用户信息
     * @return 用户信息
     */
    @Override
    public UserInfoWebVo getInfo() {

        LoginUser loginUser = LoginHelper.getLoginUser();

        SysUserVo user = sysUserMapper.selectVoById(loginUser.getUserId());
        UserInfoWebVo userInfoWebVo = baseMapper.selectVoById(user.getUserId());
        userInfoWebVo.setUserVo(user);

        UserLevel userLevel = userLevelMapper.selectById(userInfoWebVo.getUserLevelId());
        userInfoWebVo.setCurrentUserLevel(userLevel.getUserLevel());
        userInfoWebVo.setRequiredExperience(userLevel.getRequiredExperience());

        if (userLevel.getUserLevel() == 7) {
            userInfoWebVo.setUpNextExperience(0);
            userInfoWebVo.setNextUserLevel(7);
            userInfoWebVo.setLevelProgress(100);
        }else {
            userInfoWebVo.setUpNextExperience(userLevel.getRequiredExperience() - userInfoWebVo.getExperience());
            userInfoWebVo.setNextUserLevel(userLevel.getUserLevel() + 1);
            userInfoWebVo.setLevelProgress(BigDecimal.valueOf(userInfoWebVo.getExperience()).divide(BigDecimal.valueOf(userLevel.getRequiredExperience()), 2, RoundingMode.DOWN).multiply(BigDecimal.valueOf(100)).intValue());
        }

        long diffInMillis = new Date().getTime() - user.getCreateTime().getTime();
        userInfoWebVo.setRegisterDayCount(Math.max(TimeUnit.MILLISECONDS.toDays(diffInMillis), 1)); // 刚注册的为1天

        userInfoWebVo.setTodayLogin(RedisUtils.getCacheObject(CacheConstants.TODAY_USER_LOGIN_KEY + loginUser.getUserId()));

        return userInfoWebVo;

    }

    /**
     * 添加硬币
     * @param userId 用户id
     * @param type 类型 0-登录奖励, 1-消费奖励, 2-系统赠送
     * @param coinNum 硬币数量
     */
    @Override
    public void addCoin(Long userId, int type, Integer coinNum) {

        if(type == 0){
            Long count = userCoinLogMapper.selectCount(Wrappers.<UserCoinLog>lambdaQuery().likeRight(BaseEntity::getCreateTime, DateUtils.getDate()).eq(UserCoinLog::getChangeType, type));
            if (count > 0) {
                return;
            }
        }

        UserInfoWeb userInfoWeb = baseMapper.selectById(userId);
        userInfoWeb.setBalance(userInfoWeb.getBalance() + coinNum);
        baseMapper.updateById(userInfoWeb);

        UserCoinLog userCoinLog = new UserCoinLog();
        userCoinLog.setUserId(userId);
        userCoinLog.setChangeAmount(coinNum);
        userCoinLog.setChangeType(type);
        userCoinLogMapper.insert(userCoinLog);

    }

    /**
     * 添加经验
     * @param userId 用户id
     * @param type 类型 0-登录，1-观看，2-投稿，3-点赞，4-评论，5-投币
     * @param experienceNum 经验数量
     */
    @Override
    public void addLevelExperience(Long userId, int type, Integer experienceNum) {

        Long count = userLevelExperienceLogMapper.selectCount(Wrappers.<UserLevelExperienceLog>lambdaQuery().likeRight(BaseEntity::getCreateTime, DateUtils.getDate()).eq(UserLevelExperienceLog::getChangeType, type));
        if (count > (type == 5 ? BusinessConstants.USER_COIN_TRIGGER_EXPERIENCE_LIMIT : 0)) {
            return;
        }

        UserInfoWeb userInfoWeb = baseMapper.selectById(userId);

        List<UserLevel> userLevels = userLevelMapper.selectList();

        UserLevel userLevel = userLevels.stream().filter(s-> Objects.equals(s.getId(), userInfoWeb.getUserLevelId())).findFirst().get();

        userInfoWeb.setExperience(userInfoWeb.getExperience() + experienceNum);

        if (userInfoWeb.getExperience() >= userLevel.getRequiredExperience() && userInfoWeb.getUserLevelId() < userLevels.size()) {

            userInfoWeb.setUserLevelId(userInfoWeb.getUserLevelId() + 1);

        }

        baseMapper.updateById(userInfoWeb);

        UserLevelExperienceLog userLevelExperienceLog = new UserLevelExperienceLog();
        userLevelExperienceLog.setUserId(userId);
        userLevelExperienceLog.setChangeExperience(experienceNum);
        userLevelExperienceLog.setChangeType(type);
        userLevelExperienceLogMapper.insert(userLevelExperienceLog);

    }

    /**
     * 获取用户卡片信息
     * @param uId 用户id
     * @return 用户信息
     */
    @Override
    public UserInfoWebVo getCardUInfo(Long uId) {
        UserInfoWebVo userInfoWeb = baseMapper.selectVoById(uId);
        userInfoWeb.setUserVo(sysUserMapper.selectVoById(uId));
        LoginUser loginUser = LoginHelper.getLoginUser();
        if(Objects.equals(uId, loginUser.getUserId())){
            userInfoWeb.setFollowUser(false);
        }else {
            UserFollow userFollow = userFollowMapper.selectOne(Wrappers.<UserFollow>lambdaQuery().eq(UserFollow::getFollowerId, loginUser.getUserId()).eq(UserFollow::getFollowingId, uId));
            userInfoWeb.setFollowUser(userFollow != null);
        }
        return userInfoWeb;
    }

    /**
     * 获取用户附加扩展信息
     * @param uId 用户ID
     * @return 用户扩展信息
     */
    @Override
    public UserInfoWebExtVo getUserInfoExt(Long uId) {

        UserInfoWebExtVo rtnData = new UserInfoWebExtVo();

        List<VideoVo> videoList = videoMapper.selectVoList(Wrappers.<Video>lambdaQuery().eq(BaseEntity::getCreateBy, uId));
        if (CollUtil.isNotEmpty(videoList)) {

            long likeCount = 0L;
            long playCount = 0L;
            for (VideoVo videoVo : videoList) {
                likeCount = likeCount + videoVo.getLikeCount();
                playCount = playCount + videoVo.getPlayCount();
            }
            rtnData.setLikeCount(likeCount);
            rtnData.setPlayCount(playCount);

        }

        rtnData.setSubmitCount(Convert.toLong(videoList.size()));
        rtnData.setCollectionCount(collectionMapper.selectCount(Wrappers.<ContentCollection>lambdaQuery().eq(BaseEntity::getCreateBy, uId)));
        rtnData.setCollectCount(collectMapper.selectCount(Wrappers.<UserCollect>lambdaQuery().eq(BaseEntity::getCreateBy, uId)));
        return rtnData;

    }

}
